﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Windows.Controls.Ribbon;
using SHomeWorkshop.LunarConcept.Controls;
using System.Xml;
using SHomeWorkshop.LunarConcept.Tools;
using SHomeWorkshop.LunarConcept.ModifingManager;
using System.Windows;
using SHomeWorkshop.LunarConcept.Widgets;
using System.Windows.Controls;
using System.Windows.Media;

namespace SHomeWorkshop.LunarConcept.Commands
{
    /// <summary>
    /// 创建时间：2012年2月22日
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：查找部件。
    /// </summary>
    public static class FindCommand
    {
        #region 构造方法=====================================================================================================

        /// <summary>
        /// [静态][构造方法]
        /// 
        /// ——此方法会初始化并向WPF系统注册一个RoutedUICommand。
        /// </summary>
        static FindCommand()//类型构造器
        {
            routedUICmd = new RoutedUICommand(
                "FindCommand",
                "FindCommand",
                typeof(FindCommand),//创建RoutedUICommand对象
                null);//本程序考虑支持“命令模式”因此，这些命令完全没有必要直接支持快捷键。

            routedUICmd.InputGestures.Add(new KeyGesture(Key.F, ModifierKeys.Control, "Ctrl + F"));

            cmdBinding.Command = routedUICmd;
            cmdBinding.CanExecute += new CanExecuteRoutedEventHandler(cmdBinding_CanExecute);
            cmdBinding.Executed += new ExecutedRoutedEventHandler(cmdBinding_Executed);
        }

        #endregion

        #region 字段与属性===================================================================================================

        private static CommandBinding cmdBinding = new CommandBinding();
        /// <summary>
        /// 用在主窗口CommandBindings集合中的命令绑定。
        /// 
        /// 它的Command是RoutedUICommand。
        /// ——因此，RoutedUICommand是否可以运行将由CmdBinding的CanExecute事件决定。
        /// ——而且，RoutedUICommand的执行也是通过CmdBinding的Execute事件来进行的。
        /// </summary>
        public static CommandBinding CmdBinding
        {
            get { return cmdBinding; }
        }

        private static RoutedUICommand routedUICmd;
        /// <summary>
        /// [只读静态属性]表示在WPF系统中注册的一个RoutedUICommand。
        /// ——必须和CommandBinding配合才能使用。
        ///     CommandBinding要添加到主窗口的CommandBindings集合中；
        ///     RoutedUICommand则要向WPF系统注册。
        ///     
        /// ★说明：使用静态属性是因为这样在Xaml代码中比较便于绑定。
        /// </summary>
        public static RoutedUICommand RoutedUICmd
        {
            get { return routedUICmd; }
        }

        #endregion

        #region 方法=========================================================================================================

        /// <summary>
        /// 判断命令是否可以执行。
        /// ——由于可以直接调用Execute()方法，因此，即使被禁用，也不是不能执行相关功能！！！
        /// </summary>
        static void cmdBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            //考虑到性能问题，全部取消此判断。反正执行时会判断。
            //if (Globals.MainWindow == null)
            //{
            //    e.CanExecute = false; return;
            //}

            //EditorManager manager = Globals.MainWindow.EditorManager;
            //if (manager == null)
            //{
            //    e.CanExecute = false; return;
            //}

            e.CanExecute = true; return;
        }

        /// <summary>
        /// 命令被触发时，会调用本事件处理器方法。
        /// ——本方法实际上是调用ExeCute()这个静态方法来实现特定功能。
        /// </summary>
        static void cmdBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            LunarMessage.Warning(Execute());
        }

        /// <summary>
        /// [公开静态方法]即使此命令处于禁用状态，也可以通过代码调用此方法来执行特定任务！！！
        /// 
        /// 当被绑定的命令被调用（触发）时，会引发cmdBinding_Executed事件。
        /// 在cmdBinding_Executed事件处理器方法中已添加了调用Execute()方法的代码。
        /// 
        /// ——因此，触发命令，就相当于调用此方法！！！
        /// </summary>
        public static string Execute(string keyword = null)
        {
            if (Globals.MainWindow == null) return "　　未找到主窗口。";
            Globals.MainWindow.LbxOfFindResults.Items.Clear();//先清除可能存在的上次查找结果。

            EditorManager manager = Globals.MainWindow.EditorManager;
            if (manager == null) return "　　未找到页面管理器。";

            List<PageEditor> allPages = manager.GetAllPageEditors();
            if (allPages.Count == 0)
            {
                string errorMsg = "　　当前文档没有任何页面，因而也没有任何可供查找的部件。";
                Globals.MainWindow.LbxOfFindResults.Items.Add(new ListBoxItem() { Content = errorMsg });
                return errorMsg;
            }

            if (string.IsNullOrEmpty(keyword))
            {
                Dialogs.TextInputBox tibox = new Dialogs.TextInputBox(Globals.MainWindow, "请输入要查找的关键词：",
                    "查找部件：", "");

                if (tibox.ShowDialog() != true) return string.Empty;//用户取消了命令，算正常执行完毕。
                else
                {
                    keyword = tibox.TbxInput.Text;

                    if (string.IsNullOrEmpty(keyword)) return "　　要查找的关键词不能为空！";
                }
            }

            foreach (PageEditor pe in allPages)
            {
                List<Widget> allWidgets = pe.GetListOfAllWidgets();
                foreach (Widget w in allWidgets)
                {
                    if (w == null) continue;
                    XmlNode paragraphSetNode = w.ParagraphSetNode;
                    if (paragraphSetNode == null) continue;

                    string innerText = paragraphSetNode.InnerText;
                    if (innerText == null || innerText.Length == 0) continue;

                    if (innerText.Contains(keyword))
                    {
                        string trimedText = innerText.Trim();
                        trimedText = trimedText.Replace("\r", "");
                        trimedText = trimedText.Replace("\n", "");//去除换行
                        trimedText = trimedText.Replace(" ", "");//去除空格

                        FindResultItem fri = new FindResultItem(pe.Id, w.Id, w.WidgetClassLocalName,
                            (trimedText.Length > 10) ? (trimedText.Substring(0, 10) + "...") : trimedText);
                        Globals.MainWindow.LbxOfFindResults.Items.Add(fri);
                    }
                }
            }

            if (Globals.MainWindow.LbxOfFindResults.Items.Count == 0)
            {
                MessageBox.Show("未找到任何符合条件的部件。", Globals.AppName,
                    MessageBoxButton.OK, MessageBoxImage.Warning);
            }
            else
            {
                if (Globals.MainWindow.GRTools.Width.Value < 50)
                {
                    Globals.MainWindow.GRTools.Width = new GridLength(300);
                }

                Globals.MainWindow.TIResultsOfFindInDocument.IsSelected = true;
            }

            return string.Empty;
        }

        #endregion
    }

    public class FindResultItem : ListBoxItem
    {
        public FindResultItem(string pageEditorId, string widgetId, string typeName, string headerInnerText)
        {
            this.pageEditorId = pageEditorId;
            this.widgetId = widgetId;

            this.ToolTip = "[双击]或[选定后按回车]跳转到对应部件";

            TextBlock tblock = new TextBlock() { Margin = defMargin };

            tblock.Text = "部件类型：" + typeName + "\r\n部件文本：" + headerInnerText;

            this.MouseDoubleClick += new MouseButtonEventHandler(FindResultItem_MouseDoubleClick);
            this.KeyDown += new KeyEventHandler(FindResult_KeyDown);

            Border mainBorder = new Border()
            {
                BorderBrush = Brushes.Green,
                SnapsToDevicePixels = true,
                Margin = defMargin,
                BorderThickness = defThickness,
            };
            mainBorder.Child = tblock;
            this.Content = mainBorder;
        }

        void FindResultItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            LocationToWidget();
        }

        private static readonly Thickness defMargin = new Thickness(2);

        private static readonly Thickness defThickness = new Thickness(1);

        void FindResult_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Enter:
                    {
                        LocationToWidget(); break;
                    }
            }
        }

        /// <summary>
        /// 根据传入的id来查找并定位到指向的部件。
        /// </summary>
        private void LocationToWidget()
        {
            if (Globals.MainWindow == null)
            {
                MessageBox.Show("未找到主窗口", Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            EditorManager manager = Globals.MainWindow.EditorManager;
            if (manager == null)
            {
                MessageBox.Show("未找到页面管理器", Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            PageEditor destPage = manager.GetPageEditor(pageEditorId);
            if (destPage == null)
            {
                MessageBox.Show("上次查找后，此部件所在的页面可能已经被删除",
                    Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            Widget destWidget = destPage.GetWidget(widgetId);
            if (destWidget == null)
            {
                MessageBox.Show("上次查找后，此部件可能已经被删除",
                    Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            destWidget.SelectOnlySelf();

            LunarMessage.Warning(Globals.MainWindow.TryToShowWidgetInScrollViewer(destWidget));
        }

        private string pageEditorId;
        /// <summary>
        /// [只读]传入的部件ID指向的部件所在的父页面的ID。
        /// </summary>
        public string PageEditorId
        {
            get { return pageEditorId; }
            set { pageEditorId = value; }
        }

        private string widgetId;
        /// <summary>
        /// [只读]查找到的部件的ID。
        /// </summary>
        public string WidgetId
        {
            get { return widgetId; }
        }
    }
}
